#ifndef __TIP_TRACE_H__
#define __TIP_TRACE_H__

#if !WINDOWS_SYSTEM
	#error only windows system supported
#endif

#ifndef __ETL_H__
#error wwindow.h requires etl.h to be included first
#endif

#ifndef __ETLBASE_H__
#error wwindow.h requires etlbase.h to be included first
#endif

#ifndef __wMISC_H__
#error wwindow.h requires wMisc.h to be included first
#endif

#ifndef __wWINDOW_H__
#error wwindow.h requires wWindow.h to be included first
#endif

#define chSKIP_MB(expr, info, re) \
        do { if (!(expr)) \
			{TCHAR sPath[] = _T(__FILE__); etlPathStripPath(sPath);\
			wMsgbox(_T("Exception"), MB_APPLMODAL|MB_TOPMOST|MB_ICONWARNING \
			, _T("File:[%s]\nLine:[%d]\nException:[%s]"), sPath, __LINE__, _T(info)); \
				return re;}\
		} while (0)

#define chSKIP_TRACE(expr, info, re) \
        do { if (!(expr)) \
			{TCHAR sPath[] = _T(__FILE__); etlPathStripPath(sPath);\
				SYZ_TRACE(_T("[%s:%d] Exception:[%s]"), sPath, __LINE__, _T(info)); \
				return re;}\
		} while (0)

#define chSKIP_TIP_TRACE(expr, info, re) \
        do { if (!(expr)) \
			{TCHAR sPath[] = _T(__FILE__); etlPathStripPath(sPath);\
				SYZ_TRACE(_T("[%s:%d] Exception:[%s]"), sPath, __LINE__, _T(info)); \
				wTraceTip(_T("File:[%s]\nLine:[%d]\nInfo:[%s]"), sPath, __LINE__, _T(info));\
				return re;}\
		} while (0)

#define SYZ_TIP0(info) SYZ_TIP(_T(info))
#define SYZ_TIP1(info, p1) do {chString tStr;tStr.Format(_T(info), p1);SYZ_TIP((LPCTSTR)tStr);}while(false)
#define SYZ_TIP2(info, p1, p2) do {chString tStr;tStr.Format(_T(info), p1, p2);SYZ_TIP((LPCTSTR)tStr);}while(false)

#define SYZ_TIP(info) do {\
	TCHAR sPath[] = _T(__FILE__); etlPathStripPath(sPath);\
	SYZ_TRACE(_T("File:[%s:%d] Exception:[%s]"), sPath, __LINE__, info);\
	_TipTraceHelper.TraceMessage(_T("File:[%s:%d]\nInfo:[%s]"), sPath, __LINE__, info);\
	}while(false)

//////////////////////////////////////////////////////////////////////////
// 
class wPopTrayBox : public CWindowImpl<wPopTrayBox>
{
	typedef CWindowImpl<wPopTrayBox>		_wPopTrayBox;
	enum
	{
		TIMER_DELAY_HIDE = 0x10000,
		WM_POP_TIP_BOX = WM_USER+0x1001,
	};

	BEGIN_MSG_MAP(wPopTrayBox)
//		SYZ_TRACE1("%s", wTransWM_XX(uMsg));
		MESSAGE_HANDLER(WM_TIMER,				OnTimer)
		MESSAGE_HANDLER(WM_POP_TIP_BOX,			OnPopTipBox)
		MESSAGE_HANDLER(WM_ERASEBKGND,			OnEraseBKGND)
		MESSAGE_HANDLER(WM_PAINT,				OnPaint)
		MESSAGE_HANDLER(WM_CLOSE,				OnClose)
		MESSAGE_HANDLER(WM_DESTROY,				OnDestroy)
		MESSAGE_HANDLER(WM_WINDOWPOSCHANGED,	OnDelayHide)
		MESSAGE_HANDLER(WM_MOVING,				OnDelayHide)
	END_MSG_MAP()

protected:

	HWND CreateTipBox(LPCTSTR lpszTitle)
	{
		chASSERT(lpszTitle != NULL);

		RECT rectThis = GetTrayRect();
		m_dwDelayTime = 0;

		_wPopTrayBox::Create(NULL, rectThis, lpszTitle
			, WS_CAPTION|WS_SYSMENU/*|WS_CHILD*//*|WS_VISIBLE*/
			, WS_EX_TOOLWINDOW|WS_EX_TOPMOST/*|WS_EX_CLIENTEDGE*/);

		m_brBKBrush.CreateSolidBrush(RGB(230, 230, 230));
		return m_hWnd;
	}
public:
	DECLARE_WND_CLASS_EX(_T("wndClass_wPopTrayBox"), 0, COLOR_MENU);
	BOOL PopTipText(LPCTSTR lpszTipText, LPCTSTR lpszTitle, DWORD dwDelayTime)
	{
		chASSERT(lpszTipText != NULL && lpszTitle != NULL && dwDelayTime > 1000);
		if(m_hWnd == NULL)
			return FALSE;
//			CreateTipBox(_T("TraceHelper"));

		m_strTipText = lpszTipText;
		m_dwDelayTime = dwDelayTime;
		SetWindowText(lpszTitle);

		::PostMessage(m_hWnd, WM_POP_TIP_BOX, 1, 0);
		return TRUE;
	}
private:
	LRESULT OnDelayHide(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		if(::IsWindowVisible(m_hWnd))
			::SetTimer(m_hWnd, TIMER_DELAY_HIDE, m_dwDelayTime, NULL);
		return 0;
	}
	
	LRESULT OnPopTipBox(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if(wParam != 0)
		{
			::AnimateWindow(m_hWnd, 200, AW_VER_NEGATIVE|AW_SLIDE);
			RedrawWindow();
			::SetTimer(m_hWnd, TIMER_DELAY_HIDE, m_dwDelayTime, NULL);
		}
		else
		{
			::AnimateWindow(m_hWnd, 200, AW_VER_POSITIVE|AW_SLIDE|AW_HIDE);
			RECT rectThis = GetTrayRect();
			::SetWindowPos(m_hWnd, NULL, rectThis.left, rectThis.top, 0, 0, SWP_NOREDRAW|SWP_NOZORDER|SWP_NOSIZE);
		}
		return 0;
	}
	LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		ShowWindow(SW_HIDE);
		RECT rectThis = GetTrayRect();
		::SetWindowPos(m_hWnd, NULL, rectThis.left, rectThis.top, 0, 0, SWP_NOREDRAW|SWP_NOZORDER|SWP_NOSIZE);
		return 0;
	}
	
	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		m_brBKBrush.DeleteObject();
		bHandled = FALSE;
		return 0;
	}
	LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if(wParam == TIMER_DELAY_HIDE)
		{
			::KillTimer(m_hWnd, TIMER_DELAY_HIDE);
			PostMessage(WM_POP_TIP_BOX, 0, 0);
		}
		else
			bHandled = FALSE;
		return 0;
	}
	LRESULT OnEraseBKGND(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		RECT rectClient;
		GetClientRect(&rectClient);
		::FillRect((HDC)wParam, &rectClient, m_brBKBrush.m_hBrush);
		return 0;
	}
	LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		RECT rectClient;
		GetClientRect(&rectClient);
		InflateRect(&rectClient, -10, -5);

		CPaintDC dc(m_hWnd);
		::SelectObject(dc.m_hDC, GetStockObject(ANSI_VAR_FONT));
		::SetBkMode(dc.m_hDC, TRANSPARENT);
		::DrawText(dc.m_hDC, m_strTipText, m_strTipText.GetLength(), &rectClient, DT_WORDBREAK);
		return 0;
	}
	RECT GetTrayRect()
	{
		RECT rcArea;
		::SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcArea, NULL);

		rcArea.left = rcArea.right - 200;
		rcArea.top = rcArea.bottom - 130;
		return rcArea;
	}
private:
	CBrush		m_brBKBrush;
	chString	m_strTipText;
	DWORD		m_dwDelayTime;
};

class CTipTraceHelper : public wPopTrayBox
{
public:
	BOOL Initialize()
	{
		CreateTipBox(_T("TipTrace"));
		return TRUE;
	}
	void Uninitialize()
	{	
		DestroyWindow();
	}
	void __cdecl TraceMessage(LPCTSTR lpszFormat, ...)
	{
		chASSERT(lpszFormat != NULL);

		if(!IF_TRACE_ENABLE)
			return;

		va_list argList;
		va_start(argList, lpszFormat);
		
		chString strText;
		strText.FormatV(lpszFormat, argList);
		va_end(argList);
		
		chTempString strTitle = wGetModuleFileName();
		etlPathStripPath(strTitle.GetBuffer(MAX_PATH));
		
		PopTipText((LPCTSTR)strText, (LPCTSTR)strTitle, 10000);
	}
};
extern CTipTraceHelper		_TipTraceHelper;

#endif //__TIP_TRACE_H__